<?php

namespace app\data\controller\api;

use think\admin\Controller;
use think\admin\Storage;
use think\admin\storage\AliossStorage;
use think\admin\storage\LocalStorage;
use think\admin\storage\QiniuStorage;
use think\admin\storage\TxcosStorage;
use think\file\UploadedFile;
use think\response\Json;

/**
 * 文件上传接口
 * Class Upload
 * @package app\data\controller\api
 */
class Upload extends Controller
{

    public function file(): Json
    {
        if (!($file = $this->getFile()) || empty($file)) {
            $this->error('文件上传异常，文件可能过大或未上传');
        }
        $this->extension = strtolower($file->getOriginalExtension());
        if (!in_array($this->extension, explode(',', strtolower(sysconf('storage.allow_exts'))))) {
            $this->error('文件上传类型受限，请在后台配置');
        }
        if (in_array($this->extension, ['php', 'sh'])) {
            $this->error('可执行文件禁止上传到本地服务器');
        }
        [$this->safe, $this->uptype, $this->name] = [$this->getSafe(), $this->getType(), input('xkey')];
        if (empty($this->name)) $this->name = Storage::name($file->getPathname(), $this->extension, '', 'md5_file');
        if ($this->uptype === 'local') {
            $local = LocalStorage::instance();
            $realpath = dirname($realname = $local->path($this->name, $this->safe));
            file_exists($realpath) && is_dir($realpath) || mkdir($realpath, 0755, true);
            @rename($file->getPathname(), $realname);
            $info = $local->info($this->name, $this->safe, $file->getOriginalName());
        } else {
            $bina = file_get_contents($file->getRealPath());
            $info = Storage::instance($this->uptype)->set($this->name, $bina, $this->safe, $file->getOriginalName());
        }
        if (is_array($info) && isset($info['url'])) {
            $result = ['uploaded' => true, 'filename' => $this->name, 'url' => $this->safe ? $this->name : $info['url'], 'size' => $file->getSize()];
            $this->success('上传成功', $result);
        } else {
            $result = ['uploaded' => false, 'error' => ['message' => '文件处理失败，请稍候再试！']];
            $this->success('上传失败', $result);
        }
    }

    /**
     * 获取文件上传类型
     * @return boolean
     */
    private function getSafe(): bool
    {
        return boolval(input('safe', '0'));
    }

    /**
     * 获取文件上传方式
     * @return string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function getType(): string
    {
        $this->uptype = strtolower(input('uptype', ''));
        if (!in_array($this->uptype, ['local', 'qiniu', 'alioss', 'txcos'])) {
            $this->uptype = strtolower(sysconf('storage.type'));
        }
        return strtolower($this->uptype);
    }

    /**
     * 获取本地文件对象
     */
    private function getFile()
    {
        try {
            return $this->request->file('file');
        } catch (\Exception $exception) {
            $this->error(lang($exception->getMessage()));
        }
    }

    /**
     * 阿里云上传文件签名
     * @throws \think\admin\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function oss()
    {
        $data = $this->_vali([
            'name.default' => md5(time() . rand(1000, 9999)),
        ]);

        $token = AliossStorage::instance()->buildUploadToken($data['name'], 3600);
        $data['url'] = str_replace($data['name'], '', $token['siteurl'] ?? '');
        $data['policy'] = $token['policy'] ?? '';
        $data['signature'] = $token['signature'] ?? '';
        $data['OSSAccessKeyId'] = $token['keyid'] ?? '';

        $this->success('', $data);
    }

    /**
     * 上传base64图片到OSS服务器
     * @param string $imageBase64 从前端接收到的图片资源
     *
     * @return string 图片在OSS服务器上的地址
     */
    public function uploadImageBase64()
    {
        $data = $this->_vali([
            'base64_info.require' => '',
        ]);

        /** 得到文件后缀 */
        //..
        list($head, $image_data) = explode(',', $data['base64_info']); // head = data:image/png;base64 image_data = iVBORw0KGgoA..
        list($type,) = explode(';', $head);// type = data:image/png
        list(, $suffix) = explode('/', $type);// suffix = png

        /** 步骤1. 输出到本地 */
        $localDir = $_SERVER['DOCUMENT_ROOT'] . '/Temp';
        $localFilename =  rand(1000, 9999) . time(). '.' . $suffix;
        file_put_contents($localDir . '/' . $localFilename, base64_decode($image_data));

        /** 步骤2. 上传到OSS服务器,得到url */
        try {

            $bina = file_get_contents($localDir . '/' . $localFilename);
            $info = Storage::instance('alioss')->set($localFilename, $bina, $this->safe, rand(1000, 9999) . time());

        } catch (\Exception $e) {
            $URL = '';
        } finally {
            /** 步骤3. 删除本地文件 */
            unlink($localDir . '/' . $localFilename);

        }

        $this->success('', $info);
    }

}
